/*
 * @Author: EvanXU evanxu8023@163.com
 * @Date: 2024-06-24 15:09:58
 * @LastEditors: EvanXU evanxu8023@163.com
 * @LastEditTime: 2024-07-31 14:55:57
 * @FilePath: \program\USER\user_com.c
 * @Description: 
 *  xxx 
 * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. 
 */
#include "user_com.h"
#undef	LOG_LVL
#define LOG_LVL		LOG_LVL_DEBUG
#define LOG_TAG		"com_str"
#include "log.h"

/**
 * 1. 通信相关说明:
 *      (1) 支持两种通信协议MODBUS(RTU协议),STR(字符串协议)，只能由用户在系统设置中切换;
 *      (2) 两种通信协议使用同一物理链路(同一个串口)，任一时间只能使用一种协议;
 *      (3) 系统设置中的波特率，两种协议共用一个波特率参数;
 * 
 * 2. STR协议的相关说明:
 *      (1) STR协议中发送超出参数数值范围的命令，将不会得到回复;
 *      (2) STR协议中新增了进入某项功能[SDM],进入下一下功能[SDN】,返回上一项功能[SDP]命令;
 *      (3) STR协议中只有CH1,CH2波形参数在任何功能时都可以进行命令设置，其他功能下的参数设置必须首先使用SDM命令进入该功能，如调制率，压控起始数值等;
 *      (4) STR协议中需要用户输入的参数是浮点型，但在系统中存储的参数均为整数型，如频率：用户输入WMF124.057，幅度：用户输入WMA10.785,占空比：用户输入WFD51.789
 *      (5) STR协议中用户读取参数时，除频率以外，其它返回的均是整数型，如读频率：返回10.123057，读幅度：107850, 读占空比：返回51789
 * 3. MODBUS协议的相关说明：
 *      (1) MODBUS协议中发送超出参数数值范围的命令，将自动修正为临近极限值，会向主站发送正确应答命令;
 *      (2) MODBUS协议中读取频率相关的寄存器，均是将频率数值分为了整数部分和小数部分，整数部分存放于reg1,reg2,小数部分存放于reg3,reg4
 * 
*/

/* 系统用户运行参数 */
extern USER_PARA sys_user_para;
/* 字符串协议命令接收完成标志 */
static uint16_t cmd_recv_ok = FALSE;
/* 字符串协议接收字符计数 */
static uint16_t cmd_recv_cnt = 0;
/* 字符串协议命令接收最大字符数 */
#define CMD_RECV_SIZE_MAX   64
/* 字符串协议命令接受缓存 */
static uint8_t cmd_recv_buffer[CMD_RECV_SIZE_MAX] = {0};
static void send_cmd_ack(void);
extern void user_save_sys_cfg_para(SYS_CFG *cfg);

/* 回调函数 */
typedef int16_t (*_func)(const char *);
typedef struct{
	const char *cmd_str;    /* 命令头字符串 */
	_func fun_cb;           /* 命令解析回调函数 */
}cmd_list;
/* 字符串命令及回调函数一一对应列表 */
cmd_list sys_cmd_list[] =
{
/* 设置当前工作页面(也可以描述为设置信号源模式) */
    {"SDM",     cmd_set_sys_page        },      /* 设置当前工作页面 */
    {"SDN",     cmd_set_sys_next_page   },      /* 设置系统进入下一个工作页面 */
    {"SDP",     cmd_set_sys_prev_page   },      /* 设置系统进入上一个工作页面 */
    {"RDM",     cmd_get_sys_page        },      /* 读取当前工作页面 */
    {"PTL",     cmd_set_ptl_modbus      },      /* 设置通信协议为MODBUS */
    {"BPS",     cmd_set_com_bps         },      /* 设置通信协议为MODBUS */
/* CH1主波参数设置、读取 */
    {"WMW",     cmd_set_ch1_wave        },      /* 设置CH1波形 */
	{"WMF",     cmd_set_ch1_freq        },      /* 设置CH1频率 */
    {"WMA",     cmd_set_ch1_ampl        },      /* 设置CH1幅度 */
	{"WMO",     cmd_set_ch1_offset      },      /* 设置CH1偏置 */
    {"WMP",     cmd_set_ch1_phase       },      /* 设置CH1相位 */
    {"WMD",     cmd_set_ch1_duty        },      /* 设置CH1占空比 */
	{"WMS",     cmd_set_ch1_pulse       },      /* 设置CH1脉宽(脉冲波) */
    {"WMI",     cmd_set_ch1_imp         },      /* 设置CH1输出阻抗 */
    {"WMR",     cmd_set_ch1_rate        },      /* 设置CH1衰减 */
    {"WMY",     cmd_set_ch1_sym         },      /* 设置CH1对称度(三角波) */
	{"WMH",     cmd_set_ch1_rise        },      /* 设置CH1上升时间(梯形波) */
    {"WML",     cmd_set_ch1_fall        },      /* 设置CH1下降时间(梯形波) */
    {"WMN",     cmd_set_ch1_output      },      /* 设置CH1波形输出状态 */
    {"WBN",     cmd_set_ch1_ch2_output  },      /* 同时设置设置CH1/CH2波形输出状态 */

    {"RMW",     cmd_get_ch1_wave        },      /* 读取CH1波形 */
	{"RMF",     cmd_get_ch1_freq        },      /* 读取CH1频率 */
    {"RMA",     cmd_get_ch1_ampl        },      /* 读取CH1幅度 */
	{"RMO",     cmd_get_ch1_offset      },      /* 读取CH1偏置 */
    {"RMP",     cmd_get_ch1_phase       },      /* 读取CH1相位 */
    {"RMD",     cmd_get_ch1_duty        },      /* 读取CH1占空比 */
	{"RMS",     cmd_get_ch1_pulse       },      /* 读取CH1脉宽 */
    {"RMI",     cmd_get_ch1_imp         },      /* 读取CH1输出阻抗 */
    {"RMR",     cmd_get_ch1_rate        },      /* 读取CH2衰减 */
    {"RMY",     cmd_get_ch1_sym         },      /* 读取CH1对称度 */
    {"RMH",     cmd_get_ch1_rise        },      /* 读取CH1上升时间 */
    {"RML",     cmd_get_ch1_fall        },      /* 读取CH1下降时间 */
    {"RMN",     cmd_get_ch1_output      },      /* 读取CH1通道输出状态 */
/* CH2副波参数设置、读取 */
    {"WFW",     cmd_set_ch2_wave        },      /* 设置CH2波形 */
	{"WFF",     cmd_set_ch2_freq        },      /* 设置CH2频率 */
    {"WFA",     cmd_set_ch2_ampl        },      /* 设置CH2幅度 */
	{"WFO",     cmd_set_ch2_offset      },      /* 设置CH2偏置 */
    {"WFP",     cmd_set_ch2_phase       },      /* 设置CH2相位 */
    {"WFD",     cmd_set_ch2_duty        },      /* 设置CH2占空比 */
	{"WFH",     cmd_set_ch2_rise        },      /* 设置CH2上升时间(梯形波) */
    {"WFL",     cmd_set_ch2_fall        },      /* 设置CH2下降时间(梯形波) */
    {"WFY",     cmd_set_ch2_sym         },      /* 设置CH2对称度(三角波) */
    {"WFS",     cmd_set_ch2_rate        },      /* 设置CH2衰减 */
    {"WFN",     cmd_set_ch2_output      },      /* 设置CH2通道输出状态 */
	
    {"RFW",     cmd_get_ch2_wave        },      /* 读取CH2波形 */
	{"RFF",     cmd_get_ch2_freq        },      /* 读取CH2频率 */
    {"RFA",     cmd_get_ch2_ampl        },      /* 读取CH2幅度 */
	{"RFO",     cmd_get_ch2_offset      },      /* 读取CH2偏置 */
    {"RFP",     cmd_get_ch2_phase       },      /* 读取CH2相位 */
    {"RFD",     cmd_get_ch2_duty        },      /* 读取CH2占空比 */
	{"RFH",     cmd_get_ch2_rise        },      /* 读取CH2上升时间 */
    {"RFL",     cmd_get_ch2_fall        },      /* 读取CH2下降时间 */
    {"RFY",     cmd_get_ch2_sym         },      /* 读取CH2对称度 */
    {"RFS",     cmd_get_ch2_rate        },      /* 读取CH2衰减 */
    {"RFN",     cmd_get_ch2_output      },      /* 读取CH2波形输出状态 */
/* 调制输出参数设置、读取 */
    {"WPF",     cmd_set_mod_mode        },      /* 设置调制模式 */
    {"WPM",     cmd_set_mod_src         },      /* 设置调制源 */
    {"WFK",     cmd_set_mod_fsk_hop     },      /* 设置FSK跳频 */
    {"WPR",     cmd_set_mod_am_rate     },      /* 设置AM调制率 */
    {"WFM",     cmd_set_mod_fm_freq     },      /* 设置FM频偏 */
    {"WPP",     cmd_set_mod_pm_phase    },      /* 设置PM相偏 */
    {"WPO",     cmd_set_mod_manual      },      /* 手动触发模拟 */
    {"WPN",     cmd_set_mod_burst_cnt   },      /* 设置触发脉冲输出数量 */

    {"RPF",     cmd_get_mod_mode        },      /* 读取调制模式 */
    {"RPM",     cmd_get_mod_src         },      /* 读取调制源 */
    {"RFK",     cmd_get_mod_fsk_hop     },      /* 读取FSK跳频 */
    {"RPR",     cmd_get_mod_am_rate     },      /* 读取AM调制率 */
    {"RFM",     cmd_get_mod_fm_freq     },      /* 读取FM频偏 */
    {"RPP",     cmd_get_mod_pm_phase    },      /* 读取PM相偏 */
/* 触发输出参数设置、读取 */
    {"RPN",     cmd_get_burst_cnt       },      /* 读取触发脉冲输出数量 */
/* 测量计数参数设置、读取 */
    {"WCM",     cmd_set_count_mode      },      /* 设置测量计数模式 */
    {"WCG",     cmd_set_count_gate      },      /* 设置测量闸门时间 */
    {"WCC",     cmd_set_count_coupling  },      /* 设置测量耦合方式 */
    {"WCP",     cmd_set_count_start     },      /* 设置测量暂停 */
    {"WCZ",     cmd_set_count_clear     },      /* 设置计数值清零 */

    {"RCM",     cmd_get_count_mode      },      /* 读取测量计数模式 */
    {"RCG",     cmd_get_count_gate      },      /* 读取测量闸门时间 */
    {"RCC",     cmd_get_count_coupling  },      /* 读取测量耦合方式 */
    {"RCF",     cmd_get_count_freq      },      /* 读取频率测量数值 */
    {"RCC",     cmd_get_count_cnt       },      /* 读取计数数值 */
    {"RCT",     cmd_get_count_cycle     },      /* 读取周期测量数值 */
    {"RC+",     cmd_get_count_z_width   },      /* 读取正脉宽测量数值 */
    {"RC-",     cmd_get_count_f_width   },      /* 读取负脉宽测量数值 */
    {"RCD",     cmd_get_count_duty      },      /* 读取占空比测量数值 */

/* 扫描输出参数设置 */
    {"SOB",     cmd_set_sweep_obj       },      /* 设置扫描对象 */
    {"SST",     cmd_set_sweep_origin    },      /* 设置扫描起点数据 */
    {"SEN",     cmd_set_sweep_final     },      /* 设置扫描终点数据 */
    {"STI",     cmd_set_sweep_time      },      /* 设置扫描时间 */
    {"SMO",     cmd_set_sweep_mode      },      /* 设置扫描模式 */
    {"SMD",     cmd_set_sweep_dir       },      /* 设置扫描方向 */
    {"SBE",     cmd_set_sweep_sta       },      /* 设置扫描开始暂停 */
    {"SWS",     cmd_set_sweep_step      },      /* 设置扫描步进值 */
    {"SWC",     cmd_set_sweep_cnt       },      /* 设置扫描次数 */
    {"SRT",     cmd_set_sweep_rst       },      /* 设置扫描参数复位 */

//    {"SXY",     cmd_set_sweep_src       },    /* 设置扫描信源 VCO:1; SWEEP:0,[该命令不再使用] */
//    {"RXY",             NULL},                /* 读取扫描信源 VCO:1; SWEEP:0,[该命令不再使用] */
/* 压控输出参数设置 */
    {"VOB",     cmd_set_vco_obj       },        /* 设置压控对象 */
    {"VST",     cmd_set_vco_origin    },        /* 设置压控起点数据 */
    {"VEN",     cmd_set_vco_final     },        /* 设置压控终点数据 */
    {"VMO",     cmd_set_vco_mode      },        /* 设置压控模式 */
    {"VMD",     cmd_set_vco_dir       },        /* 设置压控方向 */
    {"VBE",     cmd_set_vco_sta       },        /* 设置压控开始暂停 */
/* 系统设置参数设置、读取 */
    {"USN",             NULL},              /* 保存波形参数 */
    {"ULN",             NULL},              /* 加载波形参数 */
    /* 基本设置 */
    {"UBZ",             NULL},              /* 设置按键声音 */
    {"UBL",             NULL},              /* 设置显示背光 */
    {"UBK",             NULL},              /* 设置旋钮反向 */
    {"UBI",             NULL},              /* 设置开机进入页面 */
    {"UBF",             NULL},              /* 设置系统语言 */
    {"URS",             NULL},              /* 设置恢复出厂设置 */
    {"UFC",             NULL},              /* 确认恢复出厂设置 */
    /* 通信设置 */
//    {"UCC",             NULL},              /* 设置通信开关 */
    {"UCM",             NULL},              /* 设置联机模式 */
    {"UBP",             NULL},              /* 设置通信波特率 */
    {"UTY",             NULL},              /* 设置通信协议类型 */
    {"UAD",             NULL},              /* 设置MODBUS地址 */
    {"UCR",             NULL},              /* 设置MODBUS CRC格式 */
    /* 同步设置 */
    {"USA",     cmd_set_sync_sta_add},      /* 增加同步0-5 */
    {"USD",     cmd_set_sync_sta_clear},    /* 取消同步0-5 */
    {"RSA",     cmd_get_sync_sta},          /* 读取同步参数 */
    {"USS",     cmd_set_sync_sta},          /* 设置同步参数 */
    /* 输出设置 */
    {"OFH",             NULL},              /* 设置输出频率最大值 */
    {"OFL",             NULL},              /* 设置输出频率最小值 */
    {"OAH",             NULL},              /* 设置输出幅度最大值 */
    {"OAL",             NULL},              /* 设置输出幅度最小值 */
    {"OOH",             NULL},              /* 设置输出偏置最大值 */
    {"OOL",             NULL},              /* 设置输出偏置最小值 */
    {"OST",             NULL},              /* 设置扫描停止输出状态 */
    {"UMC",         cmd_set_ch1_def_sta},   /* 设置CH1默认输出状态 */
    {"UFC",         cmd_set_ch2_def_sta},   /* 设置CH2默认输出状态 */
    /* 校准设置 */
    {"CAL",             NULL},              /* 设置校准参数 */
    /* 存储设置 */
    {"SHT",             NULL},              /* 设置截屏允许 */
    {"IMT",             NULL},              /* 设置允许导入参数 */
    {"EMT",             NULL},              /* 设置允许导出参数 */
    {"UCT",             NULL},              /* 设置允许用户自定义 */
    /* 其他设置 */
    {"UMS",             NULL},              /* 设置级联模式 */
    {"UUL",             NULL},              /* 设置级联允许 */
    {"UPA",             NULL},              /* 设置相位更新模式 */
    {"ESL",             NULL},              /* 设置自动休眠时间 */
    {"EAR",             NULL},              /* 设置任意波按键波形编号 */
    {"EOG",             NULL},              /* 设置USB-OTG允许 */
    /* 关于本机 */
    {"UID",             NULL},              /* 读取本机ID号 */
    {"UVE",             NULL},              /* 读取本机软件版本号 */
    {"UMO",             NULL},              /* 读取本机型号 */
    {"UFV",             NULL},              /* 读取本机FPGA软件版本号 */

/* 任意波 */
    {"DDS_WAVE",        NULL},      /* 开始接收任意波 */
    {"REPAIR_WAVE",     NULL},      /* 开始接收任意波 */

    /* 正弦波修复 */
    {"REPAIR_XiuFu",    NULL},      /* 正弦波修复 */
    {"<PrSTM32_START",  NULL},      /* 开始执行APP */
    {"<PrSTM32_RST",    NULL},      /* 软件复位进入boot */

/* 按键仿真 */

};

/**
 * @description: 
 * @param {char} *cmd_buff
 * @return {*}
 */
void cmd_analysis_handle_proc(const char *cmd_buff)
{
	u16 i = 0;
	u16 set_para_num = (sizeof(sys_cmd_list) / sizeof(cmd_list));

	for(i=0; i<set_para_num; i++)
	{
		if(0 == strncmp(cmd_buff, sys_cmd_list[i].cmd_str, strlen(sys_cmd_list[i].cmd_str)))
		{
            log_d("recv cmd string: %s", cmd_recv_buffer);
            /* 命令解析成功 */
			if(0 == (*sys_cmd_list[i].fun_cb)(cmd_buff))
			{
                /* 发送应答信号 */
                send_cmd_ack();
                /* 蜂鸣器提示 */
                beep_key_trig(20);
            }
            user_com_sta_update();

            /* 检查是否需要保存新的系统参数 */
            user_save_sys_cfg_para(&sys_user_para.cfg_para);
            return;
		}
	}

	beep_onoff(3, 200, 50);
	log_e("不支持该类型命令解析. %s", cmd_recv_buffer);
}

/**
 * @description:    字符串命令接受字符函数
 * 字符串命令应当以\n(0x0A)结尾
 * 如果以\r\n(0x0D 0x0A)结尾的命令，接收程序将删除\r字符，只保留\n
 * @param {u8} c    新的字符
 * @return {*}      null
 */
void string_cmd_recv_char(u8 c)
{
    if(cmd_recv_ok == TRUE)
        return;
    /* 接收到了结束字符 */
    if(c == '\n')
    {
        /* 已接收的字符个数必须大于2 */
        if(cmd_recv_cnt > 2)
            cmd_recv_ok = TRUE;
        /* 加入字符串结尾符，重置接收计数 */
        cmd_recv_buffer[cmd_recv_cnt] = '\0';
        cmd_recv_cnt = 0;
    }
    /* 换行字符自动跳过去，不写入接收缓存 */
    else if(c == '\r');
    /* 接收到其他字符将写入接收缓存,接收缓存指针自动后移 */
    else
    {
        cmd_recv_buffer[cmd_recv_cnt++] = c;
        if(cmd_recv_cnt >= CMD_RECV_SIZE_MAX)
            cmd_recv_cnt = 0;
    }
}

/**
 * @description:    发送命令应答
 * @return {*}
 */
static void send_cmd_ack(void)
{
    CMD_DATA_SEND_BUFF((u8 *)CMD_ACK_STR, strlen(CMD_ACK_STR));
}
/**
 * @description: 系统通信命令解析任务回调函数
 * @return {*}
 */
void sys_cmd_analysis_task_cb(void)
{
    /* 系统设置的通信状态处于禁止时，不进行任何数据解析 */
    if(sys_user_para.cfg_para.com_sta != TRUE)
        return;
    /* 根据系统设置进行协议解析 */
    if(sys_user_para.cfg_para.protocol_type == PTL_TYPE_STR)
    {
        if(cmd_recv_ok)
        {
            /* 解析协议， */
            cmd_analysis_handle_proc((const char *)cmd_recv_buffer);
            cmd_recv_cnt = 0;
            memset(cmd_recv_buffer, 0, sizeof(cmd_recv_buffer));
            cmd_recv_ok = FALSE;
        }
    }
    /* MODBUS协议解析 */
    else if(sys_user_para.cfg_para.protocol_type == PTL_TYPE_MODBUS)
    {
        MODS_Poll();
    }
}

static struct Timer cmd_scan_timer;
void creat_user_cmd_analysis_task(void)
{
	timer_init(&cmd_scan_timer, sys_cmd_analysis_task_cb, 50, LOOP_FOREVER);
	timer_start(&cmd_scan_timer);	
}

/**
 * @description:    用户通信协议设置
 * @return {*}      null
 */
void user_com_protocol_set(void)
{
    /* modbus通信初始化 */
    modbus_init(sys_user_para.cfg_para.modbus_slave_addr, sys_user_para.cfg_para.bps_num);
    /* 注册uart3接收回调函数 */
    if(sys_user_para.cfg_para.protocol_type == PTL_TYPE_STR)
    {
        uart3_set_rx_cb(string_cmd_recv_char);
//        uart1_set_rx_cb(NULL);
    }
    else if(sys_user_para.cfg_para.protocol_type == PTL_TYPE_MODBUS)
    {
        uart3_set_rx_cb(modbus_recv_byte);
//        uart1_set_rx_cb(modbus_recv_byte);
    }
    /* 对通信相关初始变量进行重置 */
    cmd_recv_ok = FALSE;
    cmd_recv_cnt = 0;
}

/**
 * @description:    用户通信初始化
 * 使用同一串口解析两种协议(MODBUS与STR协议，同一时刻只能解析一种协议)
 * sys_user_para.cfg_para.protocol_type 决定协议类型
 * @return {*}      null
 */
void user_com_init(void)
{
    /* 设置通信协议 */
    user_com_protocol_set();
    /* 创建命令解析任务 */
    creat_user_cmd_analysis_task();
}


